#ifndef TIMER_H
#define TIMER_H

namespace Cvekas {

/// \brief Accurate time value
///
/// Denotes time when Timer::getTimeStamp was called. 
/// Guaranteed accuracy of 1 microsecond.
class TimeStamp : public boost::totally_ordered<TimeStamp>, public boost::additive<TimeStamp>
{
public:
	TimeStamp() : value(0LL) {};
	TimeStamp(const TimeStamp& t) : value(t.value) {}
	
	inline const TimeStamp& operator=(const TimeStamp& t) 
	{ 
		value = t.value; 
		return *this; 
	}

	inline bool operator==(const TimeStamp& t) const
	{
		return value == t.value;
	}

	inline bool operator<(const TimeStamp& t) const
	{
		return value < t.value;
	}

	inline const TimeStamp& operator+=(const TimeStamp& t) 
	{
		value += t.value;
		return *this;
	}

	inline const TimeStamp& operator-=(const TimeStamp& t) 
	{
		value -= t.value;
		return *this;
	}

	int toMiliSec()
	{
		return int(value / (frequency / 1000LL));
	}

	int64 toMicroSec()
	{
		return value / (frequency / 1000000LL);
	}

private:
	friend class Timer;

	int64 value;
	static int64 frequency;
};

/// Provides time information
class Timer
{
public:
	/// Resets Timer back to 00:00. Must be called in the beginning of program.
	static void reset();
	/// Updates internal variables. Must be called once each frame.
	static void update();

	/// Returns number of frames drawn per last second.
	static int getFPS();

	/// Returns number of seconds between last frame and this frame. 
	/// Can be used to make framerate-independent animation.
	static float getTimeScale();
	/// Returns number of milliseconds between last frame and this frame.
	static int getDTimeMs();
	/// Returns number of milliseconds since last reset() call.
	static int getTimeMs();
	/// Returns TimeStamp of current moment
	static TimeStamp getTimeStamp();

	/// Converts time in milliseconds to string (Ex. 8:16).
	static std::string msToString(int time);

private:
	static int perfCounterToMs(long long time);

	static int64 perf_frequency;
	static int64 start_time;
	static int64 current_time;
	
	static int old_time_ms;
	static int current_time_ms;
	static int d_time_ms;
	static float time_scale;

	static int last_fps_update;
	static int frames_drawn;
	static int fps;
};

} // namespace

#endif